#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
#include <errno.h>
#include <jansson.h>
#include <cups/array.h>
#include "gauthenticate.h"
#include "gjob.h"
#include "logger.h"
#include "util.h"

#define JOB_SET(_prn, _key, _val) clupsdSetString(&_prn->_key, _val)

static int compare_jobs(void *first, void *second, void *data) {
	clupsd_job_t *lhs, *rhs;
 	lhs = (clupsd_job_t*)first;
 	rhs = (clupsd_job_t*)second;

	if(lhs == rhs) return 0;
	if(lhs->gid && rhs->gid)
		return strcmp(lhs->gid, rhs->gid);
	return strcmp(lhs->title, rhs->title);
}

/**
{
 "success": true,
 "jobs": [
  {
   "id": "3432682791683548017",
   "title": "CloudPrint_Architecture.pdf",
   "status": "QUEUED",
   "fileUrl": "http://docs.google.com/printing/download?id\u003d3432682791683548017",
   "ticketUrl": "http://docs.google.com/printing/fetch?output\u003dxml\u0026jobid\u003d3432682791683548017"
  }
 ]
}
**/
cups_array_t *clupsdParseJobs(gservice* service, const char *json_str) 
{
	json_error_t error;
	cups_array_t *jlist = cupsArrayNew(compare_jobs, NULL);

	json_t *root = json_loads(json_str, 0, &error);
 	if(!root) {	
		clupsdLogMessage(CLUPSD_ERROR, "line %d: %s\n", error.line, error.text);
		return NULL;
	} else {
		json_t *job_list_j = json_object_get(root, "jobs");
		if (!json_is_array(job_list_j)) {

			clupsdLogMessage(CLUPSD_NOTICE, "No jobs for selected printer on Google Cloud Print");

		} else if(json_array_size(job_list_j) > 0) {

			json_t *this_job_j = json_array_get(job_list_j, 0);
			clupsd_job_t *job = NULL;

			json_t *field_j = json_object_get(this_job_j, "id");
			if(!json_is_string(field_j)) {
				clupsdLogMessage(CLUPSD_ERROR, "Job id is not a string.");
			} else {
				job = clupsdNewJob(json_string_value(field_j));
			}

			field_j = json_object_get(this_job_j, "title");
			if(!json_is_string(field_j)) {
				clupsdLogMessage(CLUPSD_ERROR, "Title is not a string.");
			} else {
				JOB_SET(job, title, json_string_value(field_j));
			}

			field_j = json_object_get(this_job_j, "status");
			if(!json_is_string(field_j)) {
				clupsdLogMessage(CLUPSD_ERROR, "Status is not a string.");
			} else {
				JOB_SET(job, status, json_string_value(field_j));
			}

			field_j = json_object_get(this_job_j, "fileUrl");
			if(!json_is_string(field_j)) {
				clupsdLogMessage(CLUPSD_ERROR, "fileUrl is not a string.");
			} else {
				JOB_SET(job, fileUrl, json_string_value(field_j));
			}

			field_j = json_object_get(this_job_j, "ticketUrl");
			if(!json_is_string(field_j)) {
				clupsdLogMessage(CLUPSD_ERROR, "ticketUrl is not a string.");
			} else {
				JOB_SET(job, ticketUrl, json_string_value(field_j));
			}

		  if(job && job->gid != NULL) {
				cupsArrayAdd(jlist, job);			
			}
		}
	}
	json_decref(root);
	return jlist;
}


clupsd_job_t *clupsdNewJob(const char *jobid) {
	clupsd_job_t *p;
	if ((p = calloc(1, sizeof(clupsd_job_t))) == NULL) {
	    	clupsdLogMessage(CLUPSD_ERROR, "Unable to allocate memory for job-%s",
                    strerror(errno));
		return (NULL);
	}

	if (!p)
	  goto exit;

	p->gid = strdup(jobid);
	p->gid = NULL;
	p->title = NULL;
	p->status = NULL;
	p->fileUrl = NULL;
	p->ticketUrl = NULL;
exit:
        return p;
}

#define MFREE(_l) if(_l) { free(_l); _l = NULL; }

void clupsdFreeJob(clupsd_job_t *p) {
	if (!p)
	  return;
 
  MFREE(p->gid);
  MFREE(p->title);
  MFREE(p->status);
  MFREE(p->fileUrl);
  MFREE(p->ticketUrl);
	MFREE(p);
}

void clupsdFreeAllJobs(cups_array_t *a) {
	clupsd_job_t *j;

  for(j = (clupsd_job_t *)cupsArrayFirst(a); j; j = (clupsd_job_t *)cupsArrayNext(a)) {
		clupsdFreeJob(j);
  }

	cupsArrayDelete(a);
}
